﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using Un4seen.Bass;
using System.Runtime.InteropServices;
using System.ComponentModel;
using SciLorsGroovesharkAPI.Groove.Functions;
using SciLorsGroovesharkAPI.Groove.Music;

namespace Grooveshark
{
    public class StreamWrapper : IDisposable
    {
        private Stream stream;
        private int streamLength;
        private GroovesharkAudioStream groovesharkStream;

        FILECLOSEPROC myFileCloseProc;
        FILELENPROC myFileLenProc;
        FILEREADPROC myFileReadProc;
        FILESEEKPROC myFileSeekProc;

        private StreamWrapper()
        {

        }

        private StreamWrapper(GroovesharkAudioStream groovesharkStream)
        {
            this.stream = groovesharkStream.Stream;
            this.streamLength = groovesharkStream.Length;
            this.groovesharkStream = groovesharkStream;

            myFileCloseProc = new FILECLOSEPROC(MYFILECLOSEPROC);
            myFileLenProc = new FILELENPROC(MYFILELENPROC);
            myFileReadProc = new FILEREADPROC(MYFILEREADPROC);
            myFileSeekProc = new FILESEEKPROC(MYFILESEEKPROC);

            _fileProc = new BASS_FILEPROCS(myFileCloseProc, myFileLenProc, myFileReadProc, myFileSeekProc);
        }

        private static StreamWrapper currentWrapper;
        private static object currentWrapperLock = new object();
        public static StreamWrapper CreateNew_DestroyOld(GroovesharkAudioStream groovesharkStream)
        {
            lock (currentWrapperLock)
            {
                if (currentWrapper != null && !currentWrapper.IsDisposed)
                {
                    currentWrapper.Dispose();
                    currentWrapper = null;
                }
                currentWrapper = new StreamWrapper(groovesharkStream);
                return currentWrapper;
            }
        }

        public static StreamWrapper GetCurrent()
        {
            return currentWrapper;
        }

        private BASS_FILEPROCS _fileProc;
        public BASS_FILEPROCS FILEPROC
        {
            get
            {
                return _fileProc;
            }
        }

        private void MYFILECLOSEPROC(IntPtr user)
        {
            try
            {
                groovesharkStream.MarkAsDownloaded();
            }
            catch { }

            try
            {
                stream.Close();
                stream.Dispose();
                stream = null;
            }
            catch { }
        }

        public int StreamID
        {
            get;
            set;
        }

        public SearchArtist.SearchArtistResult Song
        {
            get;
            set;
        }

        private long MYFILELENPROC(IntPtr user)
        {
            return streamLength;
        }

        private int MYFILEREADPROC(IntPtr buffer, int length, IntPtr user)
        {
            try
            {
                // at first we need to create a byte[] with the size of the requested length
                byte[] data = new byte[length];
                // read the file into data
                int bytesread = stream.Read(data, 0, length);
                // and now we need to copy the data to the buffer
                // we write as many bytes as we read via the file operation
                Marshal.Copy(data, 0, buffer, bytesread);
                return bytesread;
            }
            catch { return 0; }
        }

        private bool MYFILESEEKPROC(long offset, IntPtr user)
        {
            if (stream.CanSeek)
            {
                stream.Seek(offset, SeekOrigin.Begin);
                return true;
            }
            else
                return false;
        }

        [DefaultValue(false)]
        public bool IsDisposed
        {
            get;
            private set;
        }

        public void Dispose()
        {
            MYFILECLOSEPROC(IntPtr.Zero);
            IsDisposed = true;
        }
    }
}
